//
//  SetLocationsResponse.m
//  NetMobileLocation
//
//  Created by Mehmet Sinan Şahin on 1/29/12.
//  Copyright (c) 2012 netgis. All rights reserved.
//

#import "SetLocationsResponse.h"
#import "NSString+Extensions.h"
#import "NSDate+Extensions.h"
#import "TouchXML.h"
#import "NGUtility.h"
#import "SharedPrefs.h"


NSString * STATUS_SUCCESS = @"wfs:SUCCESS";
NSString * TAG_NAME_INSERTED = @"Inserted";
NSString * TAG_NAME_UPDATED = @"Updated";
NSString * TAG_NAME_DELETED = @"Deleted";
NSString * TAG_NAME_STATUS = @"Status";
NSString * TAG_NAME_STATUS_SUCCESS = @"SUCCESS";
NSString * TAG_NAME_IS_KNOWN_DEVICE = @"IsUnknownDevice";
NSString * EX_INVALID_SESSIONID=@"EX_INVALID_SESSIONID";
//NSString * TAG_NAME_HAS_MESSAGE = @"HasMessage";
NSString * TAG_NAME_MESSAGES = @"Messages";

NSString * TEST_XML_SUCCESS_SETLOCATIONS = @"<DataRetrievingServiceResults><DataRetrievingServiceResult><PutInfoExResult><wfs:TransactionResponse xmlns:wfs=\"http://www.opengis.net/wfs/\">"
"<wfs:TransactionResult>"
"<Inserted>1</Inserted>"
"<Updated>99</Updated>"
"<Deleted>0</Deleted>"
"<wfs:Status>"
"<wfs:SUCCESS />"
"</wfs:Status>"
"</wfs:TransactionResult>"
"</wfs:TransactionResponse></PutInfoExResult><IsUnknownDevice>1</IsUnknownDevice><HasMessage>ğğ</HasMessage></DataRetrievingServiceResult><DataRetrievingServiceResult><PutInfoExResult><wfs:TransactionResponse xmlns:wfs=\"http://www.opengis.net/wfs/\">"
"<wfs:TransactionResult>"
"<Inserted>1</Inserted>"
"<Updated>0</Updated>"
"<Deleted>0</Deleted>"
"<wfs:Status>"
"<wfs:SUCCESS />"
"</wfs:Status>"
"</wfs:TransactionResult>"
"</wfs:TransactionResponse></PutInfoExResult><IsUnknownDevice>1</IsUnknownDevice><HasMessage>0</HasMessage></DataRetrievingServiceResult><DataRetrievingServiceResult><PutInfoExResult><wfs:TransactionResponse xmlns:wfs=\"http://www.opengis.net/wfs/\">"
"<wfs:TransactionResult>"
"<Inserted>1</Inserted>"
"<Updated>0</Updated>"
"<Deleted>bb</Deleted>"
"<wfs:Status>"
"<wfs:SUCCESS />"
"</wfs:Status>"
"</wfs:TransactionResult>"
"</wfs:TransactionResponse></PutInfoExResult><IsUnknownDevice>1</IsUnknownDevice><HasMessage>0</HasMessage></DataRetrievingServiceResult></DataRetrievingServiceResults>";
NSString * TEST_XML_SUCCESS_SETLOCATION = @"<DataRetrievingServiceResult><PutInfoExResult><wfs:TransactionResponse xmlns:wfs=\"http://www.opengis.net/wfs/\">"
"<wfs:TransactionResult>"
"<Inserted>1</Inserted>"
"<Updated>99</Updated>"
"<Deleted>0</Deleted>"
"<wfs:Status>"
"<wfs:SUCCESS />"
"</wfs:Status>"
"</wfs:TransactionResult>"
"</wfs:TransactionResponse></PutInfoExResult><IsUnknownDevice>1</IsUnknownDevice><HasMessage>ğğ</HasMessage></DataRetrievingServiceResult><DataRetrievingServiceResult><PutInfoExResult><wfs:TransactionResponse xmlns:wfs=\"http://www.opengis.net/wfs/\">"
"<wfs:TransactionResult>"
"<Inserted>1</Inserted>"
"<Updated>0</Updated>"
"<Deleted>0</Deleted>"
"<wfs:Status>"
"<wfs:SUCCESS />"
"</wfs:Status>"
"</wfs:TransactionResult>"
"</wfs:TransactionResponse></PutInfoExResult><IsUnknownDevice>1</IsUnknownDevice><HasMessage>0</HasMessage></DataRetrievingServiceResult><DataRetrievingServiceResult><PutInfoExResult><wfs:TransactionResponse xmlns:wfs=\"http://www.opengis.net/wfs/\">"
"<wfs:TransactionResult>"
"<Inserted>1</Inserted>"
"<Updated>0</Updated>"
"<Deleted>bb</Deleted>"
"<wfs:Status>"
"<wfs:SUCCESS />"
"</wfs:Status>"
"</wfs:TransactionResult>"
"</wfs:TransactionResponse></PutInfoExResult><IsUnknownDevice>1</IsUnknownDevice><HasMessage>0</HasMessage></DataRetrievingServiceResult>";


@implementation TransactionResult

@synthesize inserted;
@synthesize deleted;
@synthesize updated;
@synthesize status;

- (BOOL) isSuccessful {
    return [STATUS_SUCCESS indexOf:status] >= 0;
}

- (id) init:(NSString *)pInserted updated:(NSString *)pUpdated deleted:(NSString *)pDeleted status:(NSString *)pStatus {
    if (self = [super init]) {
        self.inserted = pInserted;
        self.updated = pUpdated;
        self.deleted = pDeleted;
        self.status = pStatus;
    }
    return self;
}

- (id) init {
    if (self = [super init]) {
        inserted = @"";
        updated = @"";
        deleted = @"";
        status = @"";
    }
    return self;
}

- (NSString *) description {
    return [NSString stringWithFormat:@"\nStatus: %@ \nInserted: %@ \nUpdated: %@ \nDeleted: %@\n", status, inserted, updated, deleted];
}

- (void) dealloc {
    [inserted release];
    [updated release];
    [deleted release];
    [status release];
    [super dealloc];
}

@end

@implementation TransactionResponse

@synthesize results;

- (id) init {
    if (self = [super init]) {
        results = [[[NSMutableArray alloc] init] autorelease];
    }
    return self;
}

- (void) add:(TransactionResult *)result {
    [results addObject:result];
}

- (TransactionResult *) last {
    return [results objectAtIndex:[results count] - 1];
}

- (NSString *) description {
    return [results description];
}

- (void) dealloc {
    [results release];
    [super dealloc];
}

@end

@implementation PutInfoExResult

@synthesize responses;

- (id) init {
    if (self = [super init]) {
        responses = [[[NSMutableArray alloc] init] autorelease];
    }
    return self;
}

- (void) add:(TransactionResponse *)response {
    [responses addObject:response];
}

- (TransactionResponse *) last {
    return [responses objectAtIndex:[responses count] - 1];
}

- (NSString *) description {
    return [responses description];
}

- (void) dealloc {
    [responses release];
    [super dealloc];
}

@end

@implementation Command

@synthesize _command;
@synthesize value;

- (BOOL) isUsedForDevice {
    if (_command == SEND_FREQUENCY || _command == LOCATION_SIZE || _command == MIN_TIME || _command == MIN_DISTANCE) {
        return TRUE;
    }
    return FALSE;
}

@end

@implementation Message


@synthesize Sender;
@synthesize Time;
//@synthesize Type;
//@synthesize MessageHeader;
//@synthesize MessageBody;
@synthesize Command;
@synthesize CommandParameter;
@synthesize _id;
@synthesize read;

/*
 * 1:true else false
 */
- (void) setReadStatus: (int) status {
    read = status == 1 ? TRUE : FALSE;
}

- (NSString *) description {
    return [NSString stringWithFormat:@"Sender:%@\rTime:%@\rCommand:%@\rCommandParameter:%@", 
            Sender, Time, Command, CommandParameter];
}

- (Command *) getOutCommand {
    Command *command = [[[Command alloc] init] autorelease];
    if (![NSString isEmpty:self.Command] && ![NSString isEmpty:self.CommandParameter]) {
        command._command = [self.Command intValue];
        command.value = self.CommandParameter;
    } else {
        command._command = COMMAND_UNKNOWN;
        command.value = nil;            
    }
    
    return command;
}

- (BOOL) isCommand {
    return [self getType] == COMMAND;
}

- (BOOL) isMessage {
    return [self getType] == MESSAGE;
}

/*
 * Message body, right hand of |
 */
- (NSString *) getMessageBody {
    if ([self isMessage]) {
        NSArray *strArr = [self.CommandParameter componentsSeparatedByString:@"|"];
        NSString *headerStr = [strArr objectAtIndex:1];
        return headerStr;
    }
    return @"";
}

/*
 * Header, left hand of |
 */
- (NSString *) getMessageHeader {
    if ([self isMessage]) {
        NSArray *strArr = [self.CommandParameter componentsSeparatedByString:@"|"];
        NSString *headerStr = [strArr objectAtIndex:0];
        return headerStr;
    }
    return @"";
}


- (NSString *)viewMessageBody {
    if ([self isMessage])
        return [self getMessageBody];
    else if ([self isCommand]) {
        return self.CommandParameter;
    }
    return @"Bilinmeyen Body";
}

- (NSString *)viewMessageHeader {
    if ([self isMessage])
        return [self getMessageHeader];
    else if ([self isCommand]) {
        return [NGUtility friendlyCommand:[self getOutCommand]];
    }
    return @"Bilinmeyen Header";   
}

- (MESSAGE_TYPE) getType {
    if ([self.Command isEqualToString:@"0"]) {
        return MESSAGE;
    }
    return  COMMAND;
}



@end

@implementation DataRetrievingServiceResult

@synthesize putInfoExResults;
@synthesize IsUnknownDevice;
@synthesize HasMessage;
@synthesize messages;

- (id) init {
    if (self = [super init]) {
        IsUnknownDevice = @"";
        HasMessage = @"";
        putInfoExResults = [[[NSMutableArray alloc] init] autorelease];
        messages = [[[NSMutableArray alloc] init] autorelease];
    }
    return self;
}

- (void) add:(PutInfoExResult *)result {
    [putInfoExResults addObject:result];
}

- (void) addMessage:(Message *)message {
    [messages addObject:message];
}

- (PutInfoExResult *) last {
    return [putInfoExResults objectAtIndex:[putInfoExResults count] - 1];
}

- (NSString *) description {
    return [[[[[[[putInfoExResults description] stringByAppendingString:@"\n"] stringByAppendingString:@"["] stringByAppendingString:IsUnknownDevice] stringByAppendingString:@" - "] stringByAppendingString:HasMessage] stringByAppendingString:@"]"];
}

- (void) dealloc {
    [IsUnknownDevice release];
    [HasMessage release];
    [super dealloc];
}

@end

@implementation DataRetrievingServiceResults


- (id) init {
    if (self = [super init]) {
        results = [[[NSMutableArray alloc] init] autorelease];
    }
    return self;
}

- (void) add:(DataRetrievingServiceResult *)result {
    [results addObject:result];
}

- (DataRetrievingServiceResult *) last {
    return [results objectAtIndex:[results count] - 1];
}

- (NSString *) description {
    //StringBuilder * result = [[[StringBuilder alloc] init] autorelease];
    NSString *result = [[[NSString alloc] init] autorelease];
    for (DataRetrievingServiceResult * dataRes in results) {
        for (PutInfoExResult * putResult in dataRes.putInfoExResults) {
            for (TransactionResponse * response in putResult.responses) {
                for (TransactionResult * res in response.results) {
                    result = [result stringByAppendingString:[res description]];
                }
                
            }
        }
        result = [result stringByAppendingFormat:@"%@:%@\nMessages:%@",
                  TAG_NAME_IS_KNOWN_DEVICE,
                  dataRes.IsUnknownDevice,
                  dataRes.messages];
    }
    
    return result;
}

- (BOOL) isSuccessful {
    for (DataRetrievingServiceResult * dataRes in results) {
        for (PutInfoExResult * putResult in dataRes.putInfoExResults) {
            for (TransactionResponse * response in putResult.responses) {
                for (TransactionResult * res in response.results) {
                    if (![res isSuccessful]) {
                        return NO;
                    }
                }
            }
        }
    }
    return YES;
}

- (NSMutableArray *) getMessages {
    NSMutableArray *result = [[[NSMutableArray alloc] init] autorelease];
    for (DataRetrievingServiceResult *dataRes in results) {
        [result addObjectsFromArray:dataRes.messages];
    }
    return  result;
}

- (NSMutableArray *) getCommands {
    NSMutableArray *result = [[[NSMutableArray alloc] init] autorelease];
    NSMutableArray *messages = [self getMessages];
    for (Message *message in messages) {
        [result addObject:[message getOutCommand]];
    }
    return  result;
}

- (void) dealloc {
    [results release];
    [super dealloc];
}

@end


@implementation SetLocationsResponse

@synthesize error;
@synthesize successful;
@synthesize responseXml;
@synthesize errorString;
@synthesize results;
@synthesize soapFault;
@synthesize strErrorCode;
@synthesize test;

- (id) initWithError:(NSError *)err {
    if (self = [super init]) {
        error = err;
        errorString = [err description];
    }
    return self;
}

- (id) initWithSoapFault:(SoapFault *)fault {
    if (self = [super init]) {
        soapFault = fault;
        errorString = [fault description];
    }
    return self;    
}

- (id) initWithResponseXml:(NSString *)pResponseXml {
    if (self = [super init]) {
        self.responseXml = pResponseXml;
        [self parse];
    }
    return self;
}

- (BOOL) isSuccessful {
    return ![self hasException] && [results isSuccessful];
}

- (NSMutableArray *) getMessages {
    return [results getMessages];
}

- (NSMutableArray *) getCommands {
    return [results getCommands];
}

- (BOOL) hasException {
    return ![NSString isEmpty:errorString] || ![NSString isEmpty:strErrorCode];
}

- (BOOL) needRelogin {
    return [EX_INVALID_SESSIONID isEqualToString:self.strErrorCode];
}


- (NSString *) description {
    if (![self hasException]) {
        return [results description];  
    } else {
        NSString *dateStr = [[NSDate date] toFormattedString];
        NSString *errorType = nil;
        if (soapFault != nil) {
            errorType = @"SoapFault";
        } else if (error != nil) {
            errorType = @"NSError";
        } else if (strErrorCode){
            errorType = strErrorCode;
        } else {
            errorType = @"Error Type not found";
        }
        return [NSString stringWithFormat:@"HATA:\n%@:%@", errorType, dateStr, errorString];
    }
}

- (void) parse {
    if ([NSString isEmpty:responseXml])
        return;
    
    NSLog(@"RESPONSE XML\n%@", responseXml);
    self.results = [[DataRetrievingServiceResults alloc] init];
    
    @try {
        CXMLDocument *doc = [CXMLDocument alloc];
        NSError *err = [NSError alloc];
        
        [doc initWithXMLString:responseXml options:1 error:&err];
        CXMLElement *rootElement = [doc rootElement];
        NSArray *arrayResult = [rootElement elementsForName:@"DataRetrievingServiceResult"];
        
        
        //Burada bi bug var, isunknowndevice olabilir
        //root, knownlar için DataRetrieingServiceResults->DataRetrieingServiceResult geliyor
        //root, unknowlar için DataRetrieingServiceResult olarak geliyor
        if ([arrayResult count] == 0) {
            //[arrayResult release];
            if ([[rootElement elementsForName:@"PutInfoExResult"] count] > 0) {
                arrayResult = [NSArray arrayWithObject:rootElement];
            }
        }
        //--------
        
        
        BOOL hasException = FALSE;
        if ([arrayResult count] == 0) {
            NSLog(@"%@", [rootElement name]);
            if ([[rootElement name] isEqualToString:@"MobileTrackingSystemServiceException"]) {
                hasException = TRUE;
            }
            CXMLNode *errorCode = [((CXMLElement *)rootElement) attributeForName:@"ErrorCode"];
            NSString *errorStr = [rootElement stringValue];
            NSLog(@"%@ %@", [errorCode stringValue], errorStr);
            
            self.strErrorCode = [errorCode stringValue];
            self.errorString = errorStr;

            return;
        }
        
        for (int i=0; i < [arrayResult count]; i++) {
            CXMLNode *nodeResult = [arrayResult objectAtIndex:i];
            DataRetrievingServiceResult *serviceResult = [[DataRetrievingServiceResult alloc] init];
            NSArray *arrayPutInfo = [nodeResult children];
            for (int j=0; j < [arrayPutInfo count]; j++) {
                CXMLNode *nodePutInfo = [arrayPutInfo objectAtIndex:j];
                Message *message = nil;
                if ([[nodePutInfo name] isEqualToString:TAG_NAME_IS_KNOWN_DEVICE]) {
                    serviceResult.IsUnknownDevice = [nodePutInfo stringValue];
                    continue;
                }
                /*
                else if ([[nodePutInfo name] isEqualToString:@"Exception"]) {
                    NSLog(@"%@", [((CXMLElement *)nodePutInfo) attributeForName:@"ErrorCode"]);
                    NSArray *arrayMessages = [nodePutInfo children];
                    for (int k=0; k < [arrayMessages count]; k++) {
                        CXMLNode *nodeExcetion = [arrayMessages objectAtIndex:k];
                        if (nodeExcetion != nil && [nodeExcetion kind] == XML_ELEMENT_NODE) {
                            
                        }
                    }
                }*/
                else if ([[nodePutInfo name] isEqualToString:TAG_NAME_MESSAGES]) {
                    //TODO mesajları ekle <Messages> tag'ini
                    NSArray *arrayMessages = [nodePutInfo children];
                    for (int k=0; k < [arrayMessages count]; k++) {
                        CXMLNode *nodeMessage = [arrayMessages objectAtIndex:k];
                        if (nodeMessage != nil && [nodeMessage kind] == XML_ELEMENT_NODE) {
                            message = [[Message alloc] init];
                            for (int m = 0; m < [nodeMessage childCount] ; m++) {
                                CXMLNode *node = [nodeMessage childAtIndex:m];
                                NSString *nodeName = [node name];
                                if ([nodeName isEqualToString:@"Sender"]) 
                                    message.Sender = [node stringValue];
                                else if ([nodeName isEqualToString:@"Time"]) 
                                    message.Time = [node stringValue];
                                else if ([nodeName isEqualToString:@"Command"]) 
                                    message.Command = [node stringValue];
                                else if ([nodeName isEqualToString:@"CommandParameter"]) 
                                    message.CommandParameter = [node stringValue];
                            }
                            if (message != nil)
                                [serviceResult addMessage:message];
                        }
                    }
                    continue;
                }
                
                PutInfoExResult *putInfoEx = [[PutInfoExResult alloc] init];
                NSArray *arrayTransactionResponse = [nodePutInfo children];
                for (int k=0; k < [arrayTransactionResponse count]; k++) {
                    CXMLNode *nodeTransactionResponse = [arrayTransactionResponse objectAtIndex:k];
                    if (!(nodeTransactionResponse != nil && [nodeTransactionResponse kind] == XML_ELEMENT_NODE)) {
                        continue;
                    }
                    TransactionResponse *response = [[TransactionResponse alloc] init];
                    NSArray *arrayTransactionResult = [nodeTransactionResponse children];
                    for (int l=0; l < [arrayTransactionResult count]; l++) {
                        NSString * inserted = @"";
                        NSString * updated = @"";
                        NSString * deleted = @"";
                        NSString * status = @"";
                        CXMLNode *nodeTransactionResult = [arrayTransactionResult objectAtIndex:l];
                        if (nodeTransactionResult != nil && [nodeTransactionResult kind] == XML_ELEMENT_NODE) {
                            for (int m = 0; m < [nodeTransactionResult childCount] ; m++) {
                                CXMLNode *node = [nodeTransactionResult childAtIndex:m];
                                NSString *nodeName = [node name];
                                if ([nodeName isEqualToString:TAG_NAME_INSERTED])
                                    inserted = [node stringValue];
                                else if ([nodeName isEqualToString:TAG_NAME_DELETED])
                                    deleted = [node stringValue];
                                else if ([nodeName isEqualToString:TAG_NAME_UPDATED])
                                    updated = [node stringValue];
                                else if ([nodeName isEqualToString:TAG_NAME_STATUS]) {
                                    NSArray *array = [node children];
                                    for (int kk = 0; kk < [array count]; kk++) {
                                        CXMLNode *nodeStatus = [node childAtIndex:kk];
                                        if (nodeStatus != nil && [nodeStatus kind] == XML_ELEMENT_NODE) {
                                            status = [nodeStatus name];
                                            break;
                                        }
                                    }                                
                                }
                            }
                            [response add:[[TransactionResult alloc] 
                                           init:inserted
                                           updated:updated
                                           deleted:deleted
                                           status:status]];
                            
                        }
                    }
                    [putInfoEx add:response];
                }
                [serviceResult add:putInfoEx];
            }
            [self.results add:serviceResult];
        }
        NSLog(@"%@",self.results);
    }
    @catch (NSException *exception) {
        NSString *description = [exception reason];
        //NSLog(@"%@", description);
        description = NSLocalizedString(@"No file or directory at requested location", @"");
        NSError *err = [[[NSError alloc] initWithDomain:NSPOSIXErrorDomain
                                                   code:errno userInfo:nil] autorelease];
        // Make and return custom domain error.
        NSArray *objArray = [NSArray arrayWithObjects:description, err, nil];
        NSArray *keyArray = [NSArray arrayWithObjects:NSLocalizedDescriptionKey,
                             NSUnderlyingErrorKey, nil];
        NSDictionary *eDict = [NSDictionary dictionaryWithObjects:objArray
                                                          forKeys:keyArray];
        
        self.error = [[[NSError alloc] initWithDomain:@"ng"
                                                 code:errno userInfo:eDict] autorelease];
        self.errorString = description;
        
    }
    @finally {
        
    }
    
}

- (void) processCommands {
    @try {
        NSMutableArray *commands = [self getCommands];
        for (Command *command in commands) {
            if (![command isUsedForDevice]) {
                continue;
            }
            @try {
                if (command._command == MIN_TIME) {
                    [SharedPrefs setTimeInterval:[command.value intValue]];
                } else if (command._command == MIN_DISTANCE) {
                    [SharedPrefs setDeltaDistance:[command.value intValue]];                
                } else if (command._command == SEND_FREQUENCY) {
                    [SharedPrefs setSendFrequency:[command.value intValue]];                
                } else if (command._command == LOCATION_SIZE) {
                    [SharedPrefs setLocationSize:[command.value intValue]];
                }
            }
            @catch (NSException *exception) {
                NSLog(@"%@", exception);
            }            
        }
    }
    @catch (NSException *exception) {
        NSLog(@"%@", exception);        
    }
}

+ (SetLocationsResponse *) test {
    return [[[SetLocationsResponse alloc] initWithResponseXml:TEST_XML_SUCCESS_SETLOCATIONS] autorelease];
}

- (void) dealloc {
    [responseXml release];
    [results release];
    [errorString release];
    [error release];
    [soapFault release];
    [super dealloc];
}



@end
